<?php

namespace App\Http\Controllers\Admin;

use App\Enums\AssetSourceType;
use App\Enums\AssetStatus;
use App\Enums\ProductType;
use App\Enums\TokenLockType;
use App\Enums\TokenStatus;
use App\Enums\TransStatus;
use App\Exports\BlindExport;
use App\Exports\OrderExport;
use App\Exports\ResaleExport;
use App\Http\Controllers\Controller;
use App\Jobs\DownloadsJob;
use App\Models\AgentUser;
use App\Models\Asset;
use App\Models\Download;
use App\Models\Order;
use App\Models\ProductToken;
use App\Services\WalletService;
use Illuminate\Support\Arr;
use Vinlon\Laravel\LayAdmin\Exceptions\AdminException;

class OrderController extends Controller
{
    /** @var WalletService */
    private $walletService;

    /**
     * OrderController constructor.
     */
    public function __construct(WalletService $walletService)
    {
        $this->walletService = $walletService;
    }

    /** 查询发行订单列表 */
    public function listOrders()
    {
        $query = $this->getAgentOrdersQuery(ProductType::ISSUE());

        return paginate_result($query);
    }

    /** 查询转售订单列表 */
    public function listResaleOrders()
    {
        $query = $this->getAgentOrdersQuery(ProductType::RESALE())
            ->with(['product.resale_user']);

        return paginate_result($query);
    }

    /** 查询肓盒订单列表 */
    public function listBlindBoxOrders()
    {
        $query = $this->getAgentOrdersQuery(ProductType::BLIND_BOX());

        return paginate_result($query);
    }

    /** 查询订单详情 */
    public function getOrder($id)
    {
        /** @var AgentUser $user */
        $user = auth()->user();

        return Order::query()
            ->with(['user', 'payment', 'assets'])
            ->find($id);
    }

    /** 资产重新转账 */
    public function reTransfer($orderId)
    {
        /** @var AgentUser $user */
        $user = auth()->user();
        $order = Order::query()->where('agent_id', $user->agent_id)->find($orderId);
        $product = $order->product;
        if (!$order) {
            throw new AdminException('订单未找到');
        }
        if ($order->trans_status->isNot(TransStatus::FAILED)) {
            throw new AdminException('只有资产转账的失败的订单支持该操作');
        }
        $tokens = ProductToken::query()
            ->where('lock_refer_id', $orderId)->where('lock_type', TokenLockType::ORDER)
            ->whereIn('status', [TokenStatus::FAILED, TokenStatus::LOCKED])->get();
        if (0 === count($tokens)) {
            throw new AdminException('未找到该订单对应的资产');
        }

        // 请求转账接口
        try {
            $fromMobile = ''; // 默认使用商品发布时的收款方为付款方
            $contractAddress = $product->contract_address;
            // 转售商品
            if ($product->resale_user) {
                $fromMobile = $product->resale_user->mobile;
            }
            // 肓盒商品
            if ($product->type->is(ProductType::BLIND_BOX())) {
                $contractAddress = $tokens[0]->product->contract_address;
            }
            $transResult = $this->walletService->transfer(
                $fromMobile,
                $contractAddress,
                Arr::pluck($tokens, 'token_id'),
                $order->user->wallet_address
            );
            // 更新token状态
            foreach ($tokens as $token) {
                $transHash = Arr::get($transResult, $token->token_id, 'trans_hash_not_return');
                $token->status = TokenStatus::SOLD;
                $token->save();

                // 保存资产信息
                $asset = new Asset();
                $asset->user_id = $order->user_id;
                $asset->source_type = AssetSourceType::ORDER;
                $asset->source_id = $order->id;
                $asset->contract_address = $product->contract_address;
                $asset->token_id = $token->token_id;
                $asset->trans_hash = $transHash;
                $asset->asset_status = AssetStatus::HOLD;
                $asset->save();
            }
            $order->trans_status = TransStatus::SUCCESS;
            $order->trans_fail_reason = '';
            $order->save();
        } catch (\Exception $e) {
            $failMsg = '资产转账失败: ' . $e->getMessage();
            ProductToken::query()->whereIn('id', Arr::pluck($tokens, 'id'))->update([
                'status' => TokenStatus::FAILED,
            ]);

            $order->trans_status = TransStatus::FAILED;
            $order->trans_fail_reason = $failMsg;
            $order->save();
        }
    }

    public function export()
    {
        $user = auth()->user();

        $file = '订单' . date('YmdHis') . uniqid() . '.xls';

        $download = Download::create([
            'agent_id' => 0,
            'user_id' => $user->id,
            'name' => $file,
            'url' => 'storage/' . $file,
            'status' => 0,
            'model' => OrderExport::class,
            'request' => json_encode(request()->all()),
        ]);

        dispatch(new DownloadsJob($download));
    }

    public function resaleexport()
    {
        $user = auth()->user();

        $file = '转售订单' . date('YmdHis') . uniqid() . '.xls';

        $download = Download::create([
            'agent_id' => 0,
            'user_id' => $user->id,
            'name' => $file,
            'url' => 'storage/' . $file,
            'status' => 0,
            'model' => ResaleExport::class,
            'request' => json_encode(request()->all()),
        ]);

        dispatch(new DownloadsJob($download));
    }

    public function blindExport()
    {
        $user = auth()->user();

        $file = '盲盒订单' . date('YmdHis') . uniqid() . '.xls';

        $download = Download::create([
            'agent_id' => 0,
            'user_id' => $user->id,
            'name' => $file,
            'url' => 'storage/' . $file,
            'status' => 0,
            'model' => BlindExport::class,
            'request' => json_encode(request()->all()),
        ]);

        dispatch(new DownloadsJob($download));
    }

    /*获取金额汇总*/
    public function getAgentOrderCharge()
    {
        //默认查询当天
        if (!request()->has('start_date') && !request()->has('end_date')) {
            request()->start_date = date('Y-m-d', time());
            request()->end_date = date('Y-m-d', time());
        }
        if (ProductType::ISSUE == request()->type) {
            $amount = $this->getAgentOrdersQuery(ProductType::ISSUE())->sum('order_amount');
        } elseif (ProductType::RESALE == request()->type) {
            $amount = $this->getAgentOrdersQuery(ProductType::RESALE())->with(['product.resale_user'])->sum('order_amount');
        } elseif (ProductType::BLIND_BOX == request()->type) {
            $amount = $this->getAgentOrdersQuery(ProductType::BLIND_BOX())->sum('order_amount');
        }

        return ['amount' => $amount / 100];
    }

    private function getAgentOrdersQuery(ProductType $type)
    {
        /** @var AgentUser $user */
        $user = auth()->user();

        return Order::query()
            ->with(['user', 'payment'])
            ->when(request()->keyword, function ($q) {
                return $q->where(function ($q2) {
                    $likeVal = '%' . request()->keyword . '%';
                    $q2->where('order_no', 'like', $likeVal)
                        ->orWhere('id', request()->keyword)
                        ->orWhere('product_name', 'like', $likeVal)
                        ->orWhereHas('user', function ($q1) use ($likeVal) {
                            return $q1->where('mobile', 'like', $likeVal);
                        });
                });
            })
            ->when(request()->order_status, function ($q) {
                $orderStatusArr = explode(',', request()->order_status);
                $q->whereIn('order_status', $orderStatusArr);
            })
            ->when(request()->trans_status, function ($q) {
                $transStatusArr = explode(',', request()->trans_status);
                $q->whereIn('trans_status', $transStatusArr);
            })
            ->when(request()->divide_status, function ($q) {
                $q->whereHas('payment', function ($q2) {
                    $divideStatusArr = explode(',', request()->divide_status);
                    $q2->whereIn('divide_status', $divideStatusArr);
                });
            })
            ->whereHas('product', function ($q) use ($type) {
                return $q->where('type', $type->value)
                    ->when(request()->resale_user, function ($q2) {
                        $resaleUsereVal = '%' . request()->resale_user . '%';
                        $q2->whereHas('resale_user', function ($q1) use ($resaleUsereVal) {
                            return $q1->where('mobile', 'like', $resaleUsereVal);
                        });
                    });
            })
            ->when(request()->start_date, function ($q) {
                $q->whereDate('created_at', '>=', request()->start_date);
            })
            ->when(request()->end_date, function ($q) {
                $q->whereDate('created_at', '<=', request()->end_date);
            })
            ->when(request()->agent_id, function ($q) {
                $q->where('agent_id', request()->agent_id);
            })
            ->orderByDesc('id');
    }
}
